/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.dtgenerator.api.entityInterface.resourceInfo;

import com.inspur.edp.bef.bizentity.GspBizEntityObject;
import com.inspur.edp.bef.spi.entity.CodeRuleInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.generator.apiGenerator.dataType.entityInterface.resourceInfo.ResourceInfoCtorGenerator;
import com.inspur.edp.cef.spi.jsonser.base.StringUtils;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.das.commonmodel.entity.VersionControlInfo;
import com.inspur.edp.das.commonmodel.entity.element.GspBillCodeGenerateOccasion;
import org.eclipse.jdt.core.dom.*;

public class BefResourceInfoCtorGenerator extends ResourceInfoCtorGenerator {

    private IGspCommonDataType dataType;
    protected BefResourceInfoCtorGenerator(String className, IGspCommonDataType dataType) {
        super(className, dataType);
        this.dataType = dataType;
    }

    @Override
    protected void addExtendStatements(Block block) {
        for (IGspCommonField item : dataType.getContainElements()) {
            IGspCommonElement element = (IGspCommonElement) item;

            if(!element.getBillCodeConfig().getCanBillCode())
                continue;

            if (element.getBillCodeConfig().getCodeGenerateOccasion() == GspBillCodeGenerateOccasion.SavingTime) {
                MethodInvocation beforeSaveInvocation = ast.newMethodInvocation();
                beforeSaveInvocation.setName(ast.newSimpleName("getBeforeSaveCodeRules"));
                addBeforeSaveStatements(block, element, beforeSaveInvocation);
            }
            else if (element.getBillCodeConfig().getCodeGenerateOccasion() == GspBillCodeGenerateOccasion.CreatingTime){
                MethodInvocation afterCreateInvocation = ast.newMethodInvocation();
                afterCreateInvocation.setName(ast.newSimpleName("getAfterCreateCodeRules"));
                addAfterCreateStatements(block, element, afterCreateInvocation);
            }
        }

        GspBizEntityObject obj = (GspBizEntityObject)dataType;
        if(obj.getIsRootNode()){
            VersionControlInfo versionControlInfo = obj.getBelongModel().getVersionContronInfo();
            String versionId = versionControlInfo.getVersionControlElementId();
            if(!StringUtils.isEmpty(versionId)){
                IGspCommonElement element = obj.findElement(versionId);
                if(element == null){
                    throw new RuntimeException(obj.getBelongModel().getCode()+"模型上设置的版本字段不存在");
                }
                block.statements().add(buildVersionControlStatement(element.getLabelID()));
            }
        }

    }

    private Statement buildVersionControlStatement(String labelId){
        MethodInvocation invocation =ast.newMethodInvocation();
        invocation.setName(ast.newSimpleName("setVersionControlPropertyName"));
        invocation.arguments().add(ExpressionUtils.getStringLiteral(this.ast, labelId));
        return this.ast.newExpressionStatement(invocation);
    }


    private void addBeforeSaveStatements(Block block, IGspCommonElement element, MethodInvocation beforeSaveInvocation){
        String varName = element.getLabelID() + "B4Info";
        addCodeRuleStatements(block, varName, element, beforeSaveInvocation);
    }

    private void addAfterCreateStatements(Block block, IGspCommonElement element, MethodInvocation afterCreateInvocation){
        String varName = element.getLabelID() + "AcInfo";
        addCodeRuleStatements(block, varName, element, afterCreateInvocation);
    }

    private void addCodeRuleStatements(Block block, String varName, IGspCommonElement element, MethodInvocation invocation){
        block.statements().add(getCreateInfoStatement(varName));
        block.statements().add(getSetRuleIdStatement(varName, element.getBillCodeConfig().getBillCodeID()));
        block.statements().add(getSetDicStatement(element.getLabelID(), varName, invocation));
    }

    private Statement getCreateInfoStatement(String varName) {
        TypeInfo info = new TypeInfo(CodeRuleInfo.class);
        VariableDeclarationFragment frag = this.ast.newVariableDeclarationFragment();
        frag.setName(this.ast.newSimpleName(varName));
        ClassInstanceCreation creation = this.ast.newClassInstanceCreation();
        creation.setType(info.getType(this.ast));
        frag.setInitializer(creation);
        VariableDeclarationStatement statement = this.ast.newVariableDeclarationStatement(frag);
        statement.setType(info.getType(this.ast));
        return statement;
    }

    private Statement getSetRuleIdStatement(String varName, String ruleId) {
        MethodInvocation invocation = ExpressionUtils.getMethodInvocation(this.ast, varName, "setCodeRuleId");
        invocation.arguments().add(ExpressionUtils.getStringLiteral(this.ast, ruleId));
        return this.ast.newExpressionStatement(invocation);
    }

    private Statement getSetDicStatement(String key, String ruleParamName, MethodInvocation methodInvocation) {
        MethodInvocation invocation = ExpressionUtils.getMethodInvocation(this.ast, methodInvocation, "put");
        invocation.arguments().add(ExpressionUtils.getStringLiteral(this.ast, key));
        invocation.arguments().add(this.ast.newSimpleName(ruleParamName));
        return this.ast.newExpressionStatement(invocation);
    }
}
